/*
 *    Copyright (c) 2018-2025, boss All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the boss developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: boss
 */
package com.hopes.bizz.risk.control.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hopes.bizz.common.core.util.StringUtils;
import com.hopes.bizz.common.core.validate.ValidatorUtils;
import com.hopes.bizz.risk.common.constant.RiskDicConstant;
import com.hopes.bizz.risk.control.dto.RiskUnitEventDTO;
import com.hopes.bizz.risk.control.entity.RiskControlMeasureEntity;
import com.hopes.bizz.risk.control.entity.RiskUnitEntity;
import com.hopes.bizz.risk.control.entity.RiskUnitEventEntity;
import com.hopes.bizz.risk.control.mapper.RiskUnitEventMapper;
import com.hopes.bizz.risk.control.service.RiskControlMeasureService;
import com.hopes.bizz.risk.control.service.RiskUnitEventService;
import com.hopes.bizz.risk.control.service.RiskUnitService;
import com.hopes.bizz.risk.control.vo.RiskUnitEventVO;
import com.hopes.bizz.risk.control.vo.RiskUnitVO;
import com.hopes.bizz.risk.event.dto.RiskUnitEventExcelDTO;
import com.hopes.bizz.risk.event.vo.RiskUnitEventExcelVO;
import com.hopes.bizz.risk.setting.service.RiskConfigLecService;
import com.hopes.bizz.risk.setting.service.RiskConfigLsService;
import com.hopes.boss.common.core.constant.CommonConstants;
import com.hopes.boss.common.core.exception.BizException;
import com.hopes.boss.common.entity.ValidateImportBO;
import com.hopes.boss.common.excel.vo.ErrorMessage;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 风险事件
 *
 * @author pig
 * @date 2023-07-19 16:17:44
 */
@Service
@RequiredArgsConstructor
public class RiskUnitEventServiceImpl extends ServiceImpl<RiskUnitEventMapper, RiskUnitEventEntity> implements RiskUnitEventService {

    /* 风险单元 */
    private final RiskUnitService riskUnitService;
    private final RiskConfigLsService riskConfigLsService;
    private final RiskConfigLecService riskConfigLecService;
    private final RiskControlMeasureService riskControlMeasureService;

    /* 分页查询 */
    public Page<RiskUnitEventVO> page(Page<RiskUnitEventVO> page, RiskUnitEventDTO query) {
        query.setDelFlag(CommonConstants.STATUS_NORMAL);
        Page<RiskUnitEventVO> selectPage = baseMapper.selectPageVo(page, query);
        /* 数据处理 */
        final List<RiskUnitEventVO> collect = selectPage.getRecords().stream().peek(item -> {
            final Long riskUnitId = item.getRiskUnitId();

            final RiskUnitEntity riskUnitEntity = riskUnitService.getById(riskUnitId);
            if (riskUnitEntity != null) {
                final RiskUnitVO riskUnitVO = new RiskUnitVO();
                BeanUtils.copyProperties(riskUnitEntity, riskUnitVO);
                item.setRiskUnit(riskUnitVO);
            }

        }).collect(Collectors.toList());

        final Map<Long, List<RiskUnitEventVO>> map = collect.stream().collect(Collectors.groupingBy(RiskUnitEventVO::getRiskObjectId));
        map.forEach((k,v) ->{
            v.get(0).setRowCount(v.size());
        });
        final Map<Long, List<RiskUnitEventVO>> unitMap = collect.stream().collect(Collectors.groupingBy(RiskUnitEventVO::getRiskUnitId));
        unitMap.forEach((k,v) ->{
            v.get(0).setUnitRowCount(v.size());
        });
        // 构建 vo page 对象
        final Page<RiskUnitEventVO> res = new Page<>(page.getCurrent(), page.getSize(), selectPage.getTotal());
        res.setRecords(collect);
        return res;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(RiskUnitEventDTO riskUnitEventDTO) {
        final List<RiskControlMeasureEntity> riskControlMeasureList = riskUnitEventDTO.getRiskControlMeasureList();
        if (CollectionUtil.isEmpty(riskControlMeasureList)) {
            throw new BizException("风险管控措施不可为空");
        }

        final RiskUnitEventEntity riskUnitEventEntity = new RiskUnitEventEntity();
        BeanUtils.copyProperties(riskUnitEventDTO, riskUnitEventEntity);
        // 1、计算固有风险等级
        riskUnitEventEntity.setRiskLevel(calcRiskLevelAndAfterRiskLevel(riskUnitEventEntity, RiskUnitEventEntity::getRiskValue, RiskUnitEventEntity::getRiskDesc));
        // 2、计算现状风险等级
        riskUnitEventEntity.setAfterRiskLevel(calcRiskLevelAndAfterRiskLevel(riskUnitEventEntity, RiskUnitEventEntity::getAfterRiskValue, RiskUnitEventEntity::getAfterRiskDesc));
        // 3、新增风险事件
        baseMapper.insert(riskUnitEventEntity);
        // 4、新增管控措施
        final AtomicInteger atomicInteger = new AtomicInteger(1);
        riskControlMeasureList.forEach(item -> {
            item.setRiskEventId(riskUnitEventEntity.getId());
            item.setOrderSort(atomicInteger.getAndIncrement());
            item.setRiskUnitId(riskUnitEventEntity.getRiskUnitId());
            final String validateMsg = ValidatorUtils.validateEntity(item);
            if (StringUtils.isNotEmpty(validateMsg)) {
                throw new BizException(validateMsg);
            }
        });
        return riskControlMeasureService.saveBatch(riskControlMeasureList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(RiskUnitEventDTO riskUnitEventDTO) {
        final RiskUnitEventEntity riskUnitEventEntity = new RiskUnitEventEntity();
        BeanUtils.copyProperties(riskUnitEventDTO, riskUnitEventEntity);
        final RiskUnitEventEntity riskUnitEvent = baseMapper.getById(riskUnitEventDTO.getId());
        riskUnitEventEntity.setRiskUnitId(riskUnitEvent.getRiskUnitId());
        // 1、计算固有风险等级
        riskUnitEventEntity.setRiskLevel(calcRiskLevelAndAfterRiskLevel(riskUnitEventEntity, RiskUnitEventEntity::getRiskValue, RiskUnitEventEntity::getRiskDesc));
        // 2、计算现状风险等级
        riskUnitEventEntity.setAfterRiskLevel(calcRiskLevelAndAfterRiskLevel(riskUnitEventEntity, RiskUnitEventEntity::getAfterRiskValue, RiskUnitEventEntity::getAfterRiskDesc));
        // 3、更新风险事件
        return baseMapper.updateById(riskUnitEventEntity) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeBatchByIds(Collection<?> list) {
        final List<RiskControlMeasureEntity> controlMeasureList = riskControlMeasureService.list(
                Wrappers.<RiskControlMeasureEntity>lambdaQuery().in(RiskControlMeasureEntity::getRiskEventId, list));
        if (CollectionUtil.isEmpty(controlMeasureList)) {
            return baseMapper.deleteBatchIds(list) > 0;
        }
        // 存在关联数据
        final Map<String, Long> longMap = controlMeasureList.parallelStream().filter(e ->
                Objects.nonNull(e.getRiskEventIdStr())).collect(Collectors.groupingBy(RiskControlMeasureEntity::getRiskEventIdStr, Collectors.counting()));
        if (MapUtil.isNotEmpty(longMap)) {
            final String collect = String.join(",", longMap.keySet());
            throw new BizException("暂不支持删除风险事件【" + collect + "】，请确认该风险事件是否存在关联数据！");
        }
        return baseMapper.deleteBatchIds(list) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateControlListById(RiskUnitEventDTO riskUnitEventDTO) {
        final RiskUnitEventEntity riskUnitEventEntity = baseMapper.getById(riskUnitEventDTO.getId());
        if (null == riskUnitEventEntity) {
            throw new BizException("风险事件获取失败");
        }
        riskUnitEventDTO.getRiskControlMeasureList().forEach(item -> {
            item.setRiskEventId(riskUnitEventEntity.getId());
            item.setRiskUnitId(riskUnitEventEntity.getRiskUnitId());
            final String validateMsg = ValidatorUtils.validateEntity(item);
            if (StringUtils.isNotEmpty(validateMsg)) {
                throw new BizException(validateMsg);
            }
        });
        return riskControlMeasureService.saveOrUpdateBatch(riskUnitEventDTO.getRiskControlMeasureList());
    }

    @Override
    public RiskUnitEventVO getById(Serializable id) {
        return baseMapper.getById(id);
    }

    /**
     * 计算固有风险等级 && 现状风险等级
     * @param entity 风险事件
     * @param mapper 函数映射
     * @return       等级
     */
    private Integer calcRiskLevelAndAfterRiskLevel(RiskUnitEventEntity entity, Function<RiskUnitEventEntity, Integer> mapper, Function<RiskUnitEventEntity, String> riskDescMapper) {
        if (Objects.isNull(entity.getRiskUnitId()) || Objects.isNull(mapper.apply(entity)) || Objects.isNull(riskDescMapper.apply(entity))) {
            return null;
        }
        final RiskUnitEntity riskUnit = riskUnitService.getById(entity.getRiskUnitId());
        if (StringUtil.isEmpty(riskUnit.getEvaluateMethod())) {  // 评估方法为空
            return null;
        }
        if (riskUnit.getEvaluateMethod().equals(RiskDicConstant.MODULE_LEC)) {  // LEC方法
            return riskConfigLecService.getLecRiskLevel(mapper.apply(entity));
        } else if (riskUnit.getEvaluateMethod().equals(RiskDicConstant.MODULE_LS)){  // Ls方法
            return riskConfigLsService.getLsRiskLevel(riskDescMapper.apply(entity));
        }
        return null;
    }

    @Override
    public ValidateImportBO<RiskUnitEventExcelDTO> validateImport(List<RiskUnitEventExcelDTO> excelDTOList) {
        ValidateImportBO<RiskUnitEventExcelDTO> bo = new ValidateImportBO<>();
        List<ErrorMessage> errorMessageList = new ArrayList<>();
        List<RiskUnitEventExcelDTO> saveList = new ArrayList<>(excelDTOList);
        int successNum = excelDTOList.size();
        int failedNum = 0;

        bo.setErrorMessages(errorMessageList);
        bo.setSaveList(saveList);
        bo.setSuccessNum(successNum);
        bo.setFailedNum(failedNum);
        return bo;
    }

    @Override
    public RiskUnitEventEntity importDtoToEntity(RiskUnitEventExcelDTO excelDto) {
        RiskUnitEventEntity entity= new RiskUnitEventEntity();
        BeanUtils.copyProperties(excelDto, entity);
        return entity;
    }

    @Override
    public RiskUnitEventExcelVO exportEntityToVo(RiskUnitEventEntity entity) {
        RiskUnitEventExcelVO excelVO = new RiskUnitEventExcelVO();
        BeanUtils.copyProperties(entity, excelVO);
        return excelVO;
    }


}
